﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using HYCodeBase.Math;
using HYRevitCode.CurveUtility.IntersectionUtility;
using HYRevitCode.RevitObjectCompareUtility;

namespace HYRevitCode.CurveUtility.CurveGroupSuite
{
	public static class CurveGroupManger
	{
		public static List<List<Curve>> GroupCurvesByIntersection(List<Curve> lstInputCurves)
		{
			List<List<Curve>> list = new List<List<Curve>>();
			IEnumerable<Curve> enumerable = lstInputCurves.Distinct<Curve>();
			HashSet<Curve> intersectionSet = new HashSet<Curve>();
			List<CurveIntersectionResult> list2 = FastCurveIntersectionUtility.FastCurveIntersection(enumerable.ToList<Curve>());
			List<Curve> list3 = new List<Curve>();
			foreach (CurveIntersectionResult curveIntersectionResult in list2)
			{
				list3.Add(curveIntersectionResult.LeftValue);
				list3.Add(curveIntersectionResult.RightValue);
			}
			list3 = list3.Distinct<Curve>().ToList<Curve>();
			list3.ForEach(delegate(Curve k)
			{
				intersectionSet.Add(k);
			});
			foreach (Curve item in enumerable)
			{
				if (!intersectionSet.Contains(item))
				{
					list.Add(new List<Curve>
					{
						item
					});
				}
			}
			if (list3.Count == 0)
			{
				return list;
			}
			Dictionary<Curve, HashSet<Curve>> dictionary = new Dictionary<Curve, HashSet<Curve>>();
			using (List<CurveIntersectionResult>.Enumerator enumerator = list2.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					CurveIntersectionResult oneIntersection = enumerator.Current;
					CurveGroupManger.AddIntersectionToDic(dictionary, oneIntersection, true);
					CurveGroupManger.AddIntersectionToDic(dictionary, oneIntersection, false);
				}
				goto IL_19D;
			}
			IL_138:
			Curve key = dictionary.ElementAt(0).Key;
			HashSet<Curve> hashSet = new HashSet<Curve>();
			CurveGroupManger.FindIntersectionCurveLoop(key, hashSet, dictionary);
			list.Add(hashSet.ToList<Curve>());
			foreach (Curve key2 in hashSet)
			{
				dictionary.Remove(key2);
			}
			IL_19D:
			if (dictionary.Count == 0)
			{
				return list;
			}
			goto IL_138;
		}

		public static List<List<ICurveGeter>> GroupCurvesByIntersection(List<ICurveGeter> lstInputCurveGeters, double dExtendLength)
		{
			Dictionary<Curve, ICurveGeter> dictionary = CurveGroupManger.MakeExtendCurve(lstInputCurveGeters, dExtendLength);
			List<List<Curve>> list = CurveGroupManger.GroupCurvesByIntersection(dictionary.Keys.ToList<Curve>());
			List<List<ICurveGeter>> list2 = new List<List<ICurveGeter>>();
			foreach (List<Curve> list3 in list)
			{
				List<ICurveGeter> list4 = new List<ICurveGeter>();
				foreach (Curve key in list3)
				{
					list4.Add(dictionary[key]);
				}
				list2.Add(list4);
			}
			return list2;
		}

		public static Dictionary<Curve, ICurveGeter> MakeExtendCurve(List<ICurveGeter> lstInputCurveGeters, double dExtendLength)
		{
			Dictionary<Curve, ICurveGeter> dictionary = new Dictionary<Curve, ICurveGeter>();
			foreach (ICurveGeter curveGeter in lstInputCurveGeters)
			{
				Curve useCurve = curveGeter.UseCurve;
				Curve curve = useCurve.Clone();
				curve.MakeUnbound();
				double parameter = curve.Project(useCurve.GetEndPoint(0)).Parameter;
				double parameter2 = curve.Project(useCurve.GetEndPoint(1)).Parameter;
				double num = (parameter2 - parameter) * UnitUtility.MMToFeet(dExtendLength) / useCurve.Length;
				if (useCurve is Line)
				{
					curve.MakeBound(parameter - num, parameter2 + num);
				}
				else
				{
					Arc arc = useCurve as Arc;
					XYZ xyz = arc.Evaluate(0.5, true);
					XYZ xyz2 = arc.Evaluate(parameter - num, false);
					XYZ xyz3 = arc.Evaluate(parameter2 + num, false);
					curve = Arc.Create(xyz2, xyz3, xyz);
					if (MathUtility.LessThan(curve.Length, arc.Length))
					{
						XYZ xyz4 = arc.Evaluate(parameter + num, false);
						xyz3 = arc.Evaluate(parameter2 - num, false);
						curve = Arc.Create(xyz4, xyz3, xyz);
					}
				}
				dictionary.Add(curve, curveGeter);
			}
			return dictionary;
		}

		public static bool TryTransToCloseCurveLoop(List<Curve> inputCurves, uint inputUsePrecision, out CurveLoop creatResult)
		{
			List<ICurveGeter> list = (from n in inputCurves
			select new CurveGeterBean
			{
				UseCurve = n
			}).ToList<ICurveGeter>();
			creatResult = null;
			if (CurveGroupManger.DriectTransformToCurveLoop(inputUsePrecision, ref creatResult, list))
			{
				return true;
			}
			List<KeyValuePair<ICurveGeter, bool>> list2;
			if (CurveGroupManger.TryOrderCurveByLink(list, inputUsePrecision, out list2))
			{
				list = new List<ICurveGeter>();
				foreach (KeyValuePair<ICurveGeter, bool> keyValuePair in list2)
				{
					if (!keyValuePair.Value)
					{
						list.Add(keyValuePair.Key);
					}
					else if (keyValuePair.Key.UseCurve is Line)
					{
						keyValuePair.Key.UseCurve = Line.CreateBound(keyValuePair.Key.UseCurve.GetEndPoint(1), keyValuePair.Key.UseCurve.GetEndPoint(0));
						list.Add(keyValuePair.Key);
					}
					else
					{
						if (!(keyValuePair.Key.UseCurve is Arc))
						{
							return false;
						}
						XYZ xyz = keyValuePair.Key.UseCurve.Evaluate(0.5, true);
						keyValuePair.Key.UseCurve = Arc.Create(keyValuePair.Key.UseCurve.GetEndPoint(1), keyValuePair.Key.UseCurve.GetEndPoint(0), xyz);
						list.Add(keyValuePair.Key);
					}
				}
				return CurveGroupManger.DriectTransformToCurveLoop(inputUsePrecision, ref creatResult, list);
			}
			return false;
		}

		public static bool IfInputIsCurvePolygon(List<ICurveGeter> lstInputCurveGeter, uint inputUsePrecision)
		{
			if (CurveGroupManger.CalculateNoneLinkEnd(lstInputCurveGeter, inputUsePrecision).Count != 0)
			{
				return false;
			}
			foreach (KeyValuePair<XYZ, List<ICurveGeter>> keyValuePair in CurveGroupManger.GroupCurves(lstInputCurveGeter, inputUsePrecision))
			{
				if (keyValuePair.Value.Count != 2)
				{
					return false;
				}
			}
			return true;
		}

		public static bool IfInputIsLinkCurve(List<ICurveGeter> lstInputCurveGeter, uint inputUsePrecision)
		{
			Dictionary<XYZ, List<ICurveGeter>> dictionary;
			Dictionary<XYZ, ICurveGeter> dictionary2;
			return CurveGroupManger.IfInputIsLinkCurve(lstInputCurveGeter, inputUsePrecision, out dictionary, out dictionary2);
		}

		public static bool TryOrderCurveByLink(List<ICurveGeter> lstInputCurveGeter, uint inputUsePrecision, out List<KeyValuePair<ICurveGeter, bool>> lstOrederValue)
		{
			lstOrederValue = null;
			Dictionary<XYZ, List<ICurveGeter>> dictionary;
			Dictionary<XYZ, ICurveGeter> dictionary2;
			if (!CurveGroupManger.IfInputIsLinkCurve(lstInputCurveGeter, inputUsePrecision, out dictionary, out dictionary2))
			{
				return false;
			}
			XYZEqualityComparer xyzequalityComparer = new XYZEqualityComparer();
			xyzequalityComparer.SetPrecision(inputUsePrecision);
			lstOrederValue = new List<KeyValuePair<ICurveGeter, bool>>();
			ICurveGeter curveGeter = null;
			XYZ xyz;
			if (dictionary2.Count != 0)
			{
				xyz = dictionary2.ElementAt(0).Key;
			}
			else
			{
				xyz = dictionary.ElementAt(0).Key;
			}
			int num = 0;
			while (lstOrederValue.Count != lstInputCurveGeter.Count)
			{
				num++;
				if (num > 2 * lstInputCurveGeter.Count)
				{
					break;
				}
				List<ICurveGeter> list = dictionary[xyz];
				ICurveGeter curveGeter2;
				if (list.Count == 1)
				{
					curveGeter2 = list[0];
				}
				else
				{
					curveGeter2 = list[0];
					if (list[0] == curveGeter)
					{
						curveGeter2 = list[1];
					}
				}
				bool value = !CurveGroupManger.IfInputPointIsStartPoint(xyzequalityComparer, xyz, curveGeter2);
				lstOrederValue.Add(new KeyValuePair<ICurveGeter, bool>(curveGeter2, value));
				xyz = CurveGroupManger.CalculateAnotherPoint(curveGeter2, xyz, xyzequalityComparer);
				curveGeter = curveGeter2;
			}
			return lstOrederValue.Count == lstInputCurveGeter.Count;
		}

		public static Dictionary<XYZ, ICurveGeter> CalculateNoneLinkEnd(List<ICurveGeter> lstInputCurveGeter, uint inputUsePrecision)
		{
			return CurveGroupManger.GetNoneLinkEnd(CurveGroupManger.GroupCurves(lstInputCurveGeter, inputUsePrecision));
		}

		public static Dictionary<XYZ, List<ICurveGeter>> GroupCurves(List<ICurveGeter> inputCurves, uint inputUsePrecision)
		{
			XYZEqualityComparer xyzequalityComparer = new XYZEqualityComparer();
			xyzequalityComparer.SetPrecision(inputUsePrecision);
			Dictionary<XYZ, List<ICurveGeter>> dictionary = new Dictionary<XYZ, List<ICurveGeter>>(xyzequalityComparer);
			foreach (ICurveGeter curveGeter in inputCurves)
			{
				Curve useCurve = curveGeter.UseCurve;
				CurveGroupManger.AddDic(dictionary, useCurve, curveGeter, 0);
				CurveGroupManger.AddDic(dictionary, useCurve, curveGeter, 1);
			}
			return dictionary;
		}

		private static void FindIntersectionCurveLoop(Curve inputCurve, HashSet<Curve> visitCurveSet, Dictionary<Curve, HashSet<Curve>> useLinkDic)
		{
			if (visitCurveSet.Contains(inputCurve))
			{
				return;
			}
			visitCurveSet.Add(inputCurve);
			foreach (Curve inputCurve2 in useLinkDic[inputCurve])
			{
				CurveGroupManger.FindIntersectionCurveLoop(inputCurve2, visitCurveSet, useLinkDic);
			}
		}

		private static void AddIntersectionToDic(Dictionary<Curve, HashSet<Curve>> dicCurveLink, CurveIntersectionResult oneIntersection, bool ifIsLeft)
		{
			Curve key = oneIntersection.LeftValue;
			Curve item = oneIntersection.RightValue;
			if (!ifIsLeft)
			{
				key = oneIntersection.RightValue;
				item = oneIntersection.LeftValue;
			}
			if (!dicCurveLink.ContainsKey(key))
			{
				dicCurveLink.Add(key, new HashSet<Curve>());
			}
			if (!dicCurveLink[key].Contains(item))
			{
				dicCurveLink[key].Add(item);
			}
		}

		private static void AddDic(Dictionary<XYZ, List<ICurveGeter>> returnValue, Curve useCurve, ICurveGeter oneCurve, int usePointIndex)
		{
			if (!returnValue.ContainsKey(useCurve.GetEndPoint(usePointIndex)))
			{
				returnValue.Add(useCurve.GetEndPoint(usePointIndex), new List<ICurveGeter>());
			}
			returnValue[useCurve.GetEndPoint(usePointIndex)].Add(oneCurve);
		}

		private static bool IfInputPointIsStartPoint(XYZEqualityComparer inputComparer, XYZ inputPoint, ICurveGeter inputCurve)
		{
			return CurveGroupManger.IfInputPointIsStartPoint(inputComparer, inputPoint, inputCurve.UseCurve);
		}

		public static bool IfInputPointIsStartPoint(XYZEqualityComparer inputComparer, XYZ inputPoint, Curve inputCurve)
		{
			return inputComparer.GetHashCode(inputPoint) == inputComparer.GetHashCode(inputCurve.GetEndPoint(0));
		}

		private static XYZ CalculateAnotherPoint(ICurveGeter inputCurve, XYZ inputPoint, XYZEqualityComparer inputComparer)
		{
			XYZ endPoint = inputCurve.UseCurve.GetEndPoint(0);
			if (inputComparer.GetHashCode(inputPoint) == inputComparer.GetHashCode(endPoint))
			{
				endPoint = inputCurve.UseCurve.GetEndPoint(1);
			}
			return endPoint;
		}

		private static bool IfInputIsLinkCurve(List<ICurveGeter> lstInputCurveGeter, uint inputUsePrecision, out Dictionary<XYZ, List<ICurveGeter>> groupedValue, out Dictionary<XYZ, ICurveGeter> noneLinkEnd)
		{
			groupedValue = CurveGroupManger.GroupCurves(lstInputCurveGeter, inputUsePrecision);
			noneLinkEnd = CurveGroupManger.GetNoneLinkEnd(groupedValue);
			int num = (from n in groupedValue
			where n.Value.Count == 2
			select n).Count<KeyValuePair<XYZ, List<ICurveGeter>>>();
			if (2 == noneLinkEnd.Count)
			{
				if (groupedValue.Count != num + 2)
				{
					return false;
				}
			}
			else
			{
				if (noneLinkEnd.Count != 0)
				{
					return false;
				}
				if (groupedValue.Count != num)
				{
					return false;
				}
			}
			return true;
		}

		private static Dictionary<XYZ, ICurveGeter> GetNoneLinkEnd(Dictionary<XYZ, List<ICurveGeter>> groupValue)
		{
			return (from n in groupValue
			where n.Value.Count == 1
			select n).ToDictionary((KeyValuePair<XYZ, List<ICurveGeter>> k) => k.Key, (KeyValuePair<XYZ, List<ICurveGeter>> k) => k.Value[0]);
		}

		private static bool DriectTransformToCurveLoop(uint inputUsePrecision, ref CurveLoop creatResult, List<ICurveGeter> lstUseCurveGeter)
		{
			bool result;
			try
			{
				if (CurveGroupManger.IfInputIsCurvePolygon(lstUseCurveGeter, inputUsePrecision))
				{
					creatResult = new CurveLoop();
					foreach (ICurveGeter curveGeter in lstUseCurveGeter)
					{
						creatResult.Append(curveGeter.UseCurve);
					}
					result = true;
				}
				else
				{
					result = false;
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}
	}
}
